import axios from 'axios'
import type { AxiosInstance } from 'axios'
import type { ILoadingInstance } from 'element-plus/lib/el-loading/src/loading.type'
import type { MyRequestConfig, MyRequestIntercepts } from './types'
import router from "@/router"
import store from "@/store"
import { ElLoading, ElMessage } from 'element-plus'
const DEFAULT_LOADING = true
class MyRequest {
  instance: AxiosInstance
  intercepts?: MyRequestIntercepts
  loading?: ILoadingInstance
  showLoading?: boolean
  constructor(config: MyRequestConfig) {
    this.instance = axios.create(config)
    axios.defaults.withCredentials = true
    this.intercepts = config.intercepts
    this.showLoading = config.showLoading ?? DEFAULT_LOADING
    //  独自axios实例的请求拦截器
    this.instance.interceptors.request.use(
      config.intercepts?.requestHook,
      config.intercepts?.requestHookCatch
    )
    // 独自axios实例的响应拦截器
    this.instance.interceptors.response.use(
      config.intercepts?.responseHook,
      config.intercepts?.responseHookCatch
    )
    // axios公共的请求拦截器
    this.instance.interceptors.request.use(
      (config) => {
        // console.log(this.showLoading)

        if (this.showLoading) {
          this.loading = ElLoading.service({
            lock: true,
            text: '加载中...',
            background: 'rgba(0, 0, 0, 0.8)',
            fullscreen: true
          })
        }

        return config
      },
      (error) => {
        return Promise.reject(error)
      }
    )
    // axios公共的响应拦截器
    this.instance.interceptors.response.use(
      (res) => {
        // 响应错误拦截 业务逻辑错误拦截(请求成功 返回的标志为错误)
        const code = res.data?.code
        const message = res.data?.message
        // setTimeout(() => {
        //   this.loading?.close()
        // }, 300)
        this.loading?.close()
        switch (code) {
          case 400:
            ElMessage.error(message || '参数错误')
            break
          case 0:
            ElMessage.error(message || '未知错误')
            break
        }
        return res.data
      },
      (error) => {
        this.loading?.close()
        // 请求错误拦截 一般是服务器错误(请求失败)
        const code = error.response.status
        switch (code) {
          case 404:
            ElMessage.error('请求资源找不到')
            break
          case 401:
            ElMessage.error('token令牌无效,请重新登录。')
            router.replace('/login')
            // 清空 storage 和 vuex缓存数据
            store.dispatch('clearAll')
            break
          case 403:
            ElMessage.error('您没有权限访问')
            break
          case 500:
            ElMessage.error('服务器神游中...')
            break
          default:
            ElMessage.error('服务器繁忙。请稍后重试')
            break
        }
        return Promise.reject(error)
      }
    )
  }
  // 每一个请求的响应拦截和请求拦截
  request<T>(config: MyRequestConfig<T>): Promise<T> {
    return new Promise<T>((resolve, reject) => {
      if (config.intercepts?.requestHook) {
        config = config.intercepts.requestHook(config)
      }
      if (config.showLoading === false) {
        this.showLoading = config.showLoading
      }
      try {
        this.instance.request<any, T>(config).then(res => {
          if (config.intercepts?.responseHook) {
            res = config.intercepts.responseHook(res)
          }
          this.showLoading = DEFAULT_LOADING
          resolve(res)
        })
      } catch (err) {
        this.showLoading = DEFAULT_LOADING
        reject(err)
      }
    })
  }
  get<T = any>(config: MyRequestConfig<T>): Promise<T> {

    return this.request<T>({ ...config, method: "GET" })

  }
  post<T = any>(config: MyRequestConfig<T>): Promise<T> {

    return this.request<T>({ ...config, method: "POST" })

  }
  put<T = any>(config: MyRequestConfig<T>): Promise<T> {

    return this.request<T>({ ...config, method: "PUT" })

  }
  delete<T = any>(config: MyRequestConfig<T>): Promise<T> {

    return this.request<T>({ ...config, method: "DELETE" })

  }
  patch<T = any>(config: MyRequestConfig<T>): Promise<T> {

    return this.request<T>({ ...config, method: "PATCH" })

  }
}

export default MyRequest
